package it.unicam.ids.pvm.data.mysql;

import it.unicam.ids.pvm.data.CasellaDAO;
import it.unicam.ids.pvm.data.DAOException;
import it.unicam.ids.pvm.distributore.Casella;
import it.unicam.ids.pvm.distributore.Lato;
import it.unicam.ids.pvm.distributore.Prodotto;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

/**
 * La classe rappresenta un'implementazione dell'interfaccia CasellaDAO,
 * relativa al DBMS MySQL.
 * 
 * @author Luca Iachini, Valerio Iachini, Alessandro Cardenà
 * 
 */
public class MySQLCasellaDAO implements CasellaDAO {
	final String sqlDelete = "DELETE FROM casella WHERE etichetta = ?";
	final String sqlInsert = "INSERT INTO casella (etichetta,prodotto,quantita,lato) VALUES (?,?,?,?)";
	final String sqlUpdate = "UPDATE casella SET etichetta=?, prodotto = ?, quantita = ?, lato = ? WHERE etichetta = ?";
	final String sqlSelectAll = "SELECT etichetta,prodotto,quantita,lato FROM casella ORDER BY etichetta";
	final String sqlSelectCasella = "SELECT prodotto,quantita,lato FROM casella WHERE etichetta = ?";
	final String sqlCount = "SELECT COUNT(*) FROM casella";
	private Prodotto[] prodotti;

	/**
	 * Il metodo restituisce il prodotto selezionato dal codice.
	 * 
	 * @param codice
	 *            codice associato al prodotto.
	 * @return prodotto prodotto cercato.
	 * @throws DAOException
	 */

	private Prodotto getProdotto(String codice) throws DAOException {
		if (prodotti == null) {
			MySQLProdottoDAO prodottoDAO = (MySQLProdottoDAO) MySQLDAOFactory
					.getDAOFactory().getProdottoDAO();
			prodotti = prodottoDAO.findAllProdotti();
		}
		for (int i = 0; i < prodotti.length; i++) {
			if (prodotti[i].getCodice().compareTo(codice) == 0)
				return prodotti[i];
		}
		return null;
	}

	@Override
	public void delete(Casella casella) throws DAOException {
		Connection conn = MySQLDAOFactory.createConnection();
		PreparedStatement ps = null;
		boolean error = false;
		try {
			ps = conn.prepareStatement(sqlDelete);
			ps.setString(1, casella.getEtichetta());
			ps.executeUpdate();
		} catch (SQLException e) {
			error = true;
		} finally {
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					error = true;
				}
			}
			if (error)
				throw new DAOException(
						"Errore nella cancellazione della casella");
		}
	}

	@Override
	public Casella[] findAllCaselle() throws DAOException {
		Casella[] caselle = null;
		PreparedStatement ps = null;
		boolean error = false;
		ResultSet rs = null;
		Connection conn = MySQLDAOFactory.createConnection();
		try {
			ps = conn.prepareStatement(sqlSelectAll);
			rs = ps.executeQuery();
			caselle = new Casella[getRowCount()];
			for (int i = 0; rs.next(); i++) {
				String etichetta = rs.getString("etichetta");
				String codProdotto = rs.getString("prodotto");
				int quantita = rs.getInt("quantita");
				Lato lato = Lato.valueOf(rs.getString("lato"));
				Prodotto p = null;
				if (codProdotto != null)
					p = getProdotto(codProdotto);
				caselle[i] = new Casella(etichetta, lato, p, quantita);
			}
		} catch (Exception e) {
			error = true;
		} finally {
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					error = true;
				}
				if (rs != null)
					try {
						rs.close();
					} catch (SQLException e) {
						error = true;
					}
			}
			if (error)
				throw new DAOException(
						"Errore nel recupero dei dati riguardanti le caselle");
		}
		return caselle;
	}

	@Override
	public Casella findByEtichetta(String etichetta) throws DAOException {
		Casella casella = null;
		PreparedStatement ps = null;
		boolean error = false;
		ResultSet rs = null;
		Connection conn = MySQLDAOFactory.createConnection();
		try {
			ps = conn.prepareStatement(sqlSelectAll);
			rs = ps.executeQuery();
			if (rs.next()) {
				String codProdotto = rs.getString("prodotto");
				int quantita = rs.getInt("quantita");
				Lato lato = Lato.valueOf(rs.getString("lato"));
				casella = new Casella(etichetta, lato,
						getProdotto(codProdotto), quantita);
			}
		} catch (Exception e) {
			error = true;
		} finally {
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					error = true;
				}
				if (rs != null)
					try {
						rs.close();
					} catch (SQLException e) {
						error = true;
					}
			}
			if (error)
				throw new DAOException(
						"Errore nel recupero dei dati riguardanti la casella : "
								+ etichetta);
		}
		return casella;
	}

	@Override
	public void insert(Casella casella) throws DAOException {
		Connection conn = MySQLDAOFactory.createConnection();
		PreparedStatement ps = null;
		boolean error = false;
		try {
			ps = conn.prepareStatement(sqlInsert);
			ps.setString(1, casella.getEtichetta());
			if (casella.getProdotto() != null)
				ps.setString(2, casella.getProdotto().getCodice());
			else
				ps.setNull(2, Types.VARCHAR);
			ps.setInt(3, casella.getQuantita());
			ps.setString(4, casella.getLato().name());
			ps.executeUpdate();
		} catch (SQLException e) {
			error = true;
		} finally {
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					error = true;
				}
			}
			if (error)
				throw new DAOException("Errore nell'inserimento della casella");
		}

	}

	@Override
	public void update(Casella casella, String oldEtichetta) throws DAOException {
		Connection conn = MySQLDAOFactory.createConnection();
		PreparedStatement ps = null;
		boolean error = false;
		try {
			ps = conn.prepareStatement(sqlUpdate);
			ps.setString(1, casella.getEtichetta());
			if (casella.getProdotto() != null)
				ps.setString(2, casella.getProdotto().getCodice());
			else
				ps.setNull(2, Types.VARCHAR);
			ps.setInt(3, casella.getQuantita());
			ps.setString(4, casella.getLato().name());
			ps.setString(5, oldEtichetta);
			ps.executeUpdate();
		} catch (SQLException e) {
			error = true;
		} finally {
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					error = true;
				}
			}
			if (error)
				throw new DAOException(
						"Errore nell'aggiornamento della casella");
		}

	}

	/**
	 * Il metodo restituisce il numero delle righe della tabella relativa alle
	 * casselle del database.
	 * 
	 * @return count numero delle righe.
	 * @throws SQLException
	 * @throws DAOException
	 *             messaggio d'errore relativo al conteggio delle righe.
	 */

	private int getRowCount() throws SQLException, DAOException {
		int count = 0;
		Connection conn = MySQLDAOFactory.createConnection();
		PreparedStatement ps = null;
		ResultSet rs = null;
		boolean error = false;
		try {
			ps = conn.prepareStatement(sqlCount);
			rs = ps.executeQuery();
			rs.next();
			count = rs.getInt(1);
		} catch (SQLException e) {
			error = true;
		} finally {
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					error = true;
				}
				if (rs != null)
					rs.close();
			}
			if (error)
				throw new DAOException(
						"Errore nell'aggiornamento della casella");
		}
		return count;
	}
}